package com.hzw.saas.service.storage.service;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hzw.saas.api.storage.IResourceFileService;
import com.hzw.saas.api.storage.IResourceFolderService;
import com.hzw.saas.api.storage.IStorageService;
import com.hzw.saas.api.storage.IUserSpaceService;
import com.hzw.saas.api.storage.bo.StorageCapacityBO;
import com.hzw.saas.api.storage.bo.StorageSpaceCapacityBO;
import com.hzw.saas.api.storage.bo.UserSpaceBO;
import com.hzw.saas.api.storage.enums.ResourceStatusEnum;
import com.hzw.saas.api.storage.enums.StorageSpaceEnum;
import com.hzw.saas.api.user.IUserRightsService;
import com.hzw.saas.api.user.bo.UserStorageRightsBO;
import com.hzw.saas.api.user.constant.UserRightsConsts;
import com.hzw.saas.api.workspace.IWorkspaceResourceService;
import com.hzw.saas.common.config.query.LogicQuery;
import com.hzw.saas.common.util.UnitConvertUtils;
import com.hzw.saas.common.util.enums.StorageUnitEnum;
import com.hzw.saas.common.util.exception.ForbiddenException;
import com.hzw.saas.common.util.exception.LockedException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;


/**
 * @author zzl
 * @since 05/25/2021
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class StorageServiceImpl implements IStorageService {

    // 默认有效小数位
    private static final int DEFAULT_SCALE = 2;

    private final IUserRightsService userRightsService;
    private final IUserSpaceService userSpaceService;
    private final IResourceFileService fileService;
    private final IResourceFolderService folderService;
    private final IWorkspaceResourceService wsFileService;

    @Override
    public StorageCapacityBO getStorageCapacity(String userId, boolean checkExpired) {
        StorageCapacityBO result = new StorageCapacityBO();
        if (StrUtil.isBlank(userId)) return result;

        // 总容量
        Optional<UserStorageRightsBO> userRights = Optional.ofNullable(userRightsService.getStorageRights(userId));
        String totalSizeText = userRights.map(UserStorageRightsBO::getCloudStorageSize).orElse(UserRightsConsts.DEFAULT_CLOUD_STORAGE_SIZE);
        Date expireTime = userRights.map(UserStorageRightsBO::getCloudStorageExpireTime).orElse(null);

        if (checkExpired && DateUtil.compare(expireTime, new Date()) < 0) {
            throw new ForbiddenException("存储空间已过期");
        }

        // 已使用容量
        // TODO: ZZL@09/30/2021 暂时使用总容量上限，不分解各空间容量上限
        List<String> spaceIdList = StorageSpaceEnum.listCodes(StorageSpaceEnum.rootCode(), null, true);
        // 统计未删除且所有完整性状态的文件
        List<Integer> deletedStatus = ResourceStatusEnum.DELETED.groupCodes();
        long usedSize = fileService.countSizeByUser(userId, spaceIdList, LogicQuery.ne(deletedStatus), LogicQuery.none());
        // 云桌面空间文件大小统计
        usedSize += wsFileService.getFileSize(userId, "/");
        /*long usedSize = 0L;
        for (String spaceId : spaceIdList) {
            StorageSpaceCapacityBO spaceCapacity = this.getStorageCapacity(userId, spaceId);
            usedSize += spaceCapacity.getUsedSize();
            result.getSpaceCapacities().add(spaceCapacity);
        }*/
        // 归总
        this.setCapacity(result, totalSizeText, usedSize, expireTime);
        return result;
    }

    @Override
    public StorageSpaceCapacityBO getStorageCapacity(String userId, String spaceId, boolean checkExpired) {
        if (StrUtil.hasBlank(userId, spaceId))
            return new StorageSpaceCapacityBO();
        StorageSpaceEnum spaceEnum = StorageSpaceEnum.assertInstance(spaceId);
        // user space
        UserSpaceBO userSpaceBO = userSpaceService.get(userId, spaceId);
        // 如果没有数据就初始化
        if (Objects.isNull(userSpaceBO)) {
            userSpaceService.initUserSpace(userId);
            userSpaceBO = userSpaceService.get(userId, spaceId);
        }
        Optional<UserSpaceBO> userSpace = Optional.ofNullable(userSpaceBO);
        String totalSizeText = userSpace.map(UserSpaceBO::getSpaceSize).orElse(UserRightsConsts.DEFAULT_CLOUD_STORAGE_SIZE);
        Date expireTime = userSpace.map(UserSpaceBO::getExpireTime).orElse(null);

        if (checkExpired && DateUtil.compare(expireTime, new Date()) < 0) {
            throw new ForbiddenException("存储空间已过期");
        }

        // used size
        long usedSize = 0L;
        if (Objects.equals(spaceId, StorageSpaceEnum.CLOUD_DESKTOP_SPACE.getCode())) {
            usedSize = wsFileService.getFileSize(userId, "/");
        } else {
            // 统计未删除且所有完整性状态的文件
            List<Integer> deletedStatus = ResourceStatusEnum.DELETED.groupCodes();
            usedSize = fileService.countSizeByUser(userId, ListUtil.toList(spaceId), LogicQuery.ne(deletedStatus), LogicQuery.none());
        }
        StorageSpaceCapacityBO spaceCapacity = new StorageSpaceCapacityBO();
        spaceCapacity.setSpaceId(spaceId);
        spaceCapacity.setSpaceText(spaceEnum.getText());
        this.setCapacity(spaceCapacity, totalSizeText, usedSize, expireTime);
        return spaceCapacity;
    }

    @Override
    public void assertNotOverSize(String userId, String spaceId, long length) {
        if (!StorageSpaceEnum.isLimit(spaceId)) {
            return;
        }
        // TODO: ZZL@09/30/2021 暂时使用总容量上限，不分解各空间容量上限
        // StorageCapacityBO storageCapacity = this.getStorageCapacity(userId, spaceId);
        Optional<StorageCapacityBO> storageCapacity = Optional.ofNullable(this.getStorageCapacity(userId, true));
        long usedSize = storageCapacity.map(StorageCapacityBO::getUsedSize).orElse(0L);
        long totalSize = storageCapacity.map(StorageCapacityBO::getTotalSize).orElse(0L);
        if (usedSize + length > totalSize) {
            throw new ForbiddenException("存储空间容量不足");
        }
    }

    @Override
    public void assertNotOverSize(String userId, String spaceId, List<String> fileIds, List<String> folderIds) {
        if (!StorageSpaceEnum.isLimit(spaceId)) {
            return;
        }
        // TODO: ZZL@09/30/2021 暂时使用总容量上限，不分解各空间容量上限
        // StorageCapacityBO storageCapacity = this.getStorageCapacity(userId, spaceId);
        Optional<StorageCapacityBO> storageCapacity = Optional.ofNullable(this.getStorageCapacity(userId, true));
        long usedSize = storageCapacity.map(StorageCapacityBO::getUsedSize).orElse(0L);
        long totalSize = storageCapacity.map(StorageCapacityBO::getTotalSize).orElse(0L);

        long filesSize = 0L;
        // 排除已删除的文件
        LogicQuery<Integer> status = LogicQuery.ne(ResourceStatusEnum.DELETED.groupCodes());
        // 统计所有完整性状态的文件
        LogicQuery<Integer> integrity = LogicQuery.none();
        filesSize += fileService.countSizeBySupId(fileIds, status, integrity);
        filesSize += folderService.countSize(folderIds, status, integrity);
        if (usedSize + filesSize > totalSize) {
            throw new LockedException("存储空间容量不足");
        }
    }

    private void setCapacity(StorageCapacityBO capacity, String totalSizeText, long usedSize, Date expireDate) {
        long totalSize = UnitConvertUtils.convertStorage(totalSizeText, StorageUnitEnum.BYTE).longValue();
        capacity.setTotalSize(totalSize);
        capacity.setUsedSize(usedSize);
        capacity.setExpireTime(expireDate);
        capacity.setTotalSizeText(totalSizeText);
        this.setText(capacity);
    }

    private void setText(StorageCapacityBO capacity) {
        long remainSize = capacity.getTotalSize() - capacity.getUsedSize();
        if (remainSize < 0)
            remainSize = 0;
        capacity.setUsedSizeText(UnitConvertUtils.suitableStorageText(capacity.getUsedSize(), DEFAULT_SCALE));
        capacity.setRemainSizeText(UnitConvertUtils.suitableStorageText(remainSize, DEFAULT_SCALE));
    }
}
